package org.opens.netty.agreement;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HttpAgreementServer {

    public static void main(String[] args) {
        NioEventLoopGroup bossEventLoopGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerEventLoopGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.group(bossEventLoopGroup, workerEventLoopGroup);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                /**
                 * 会在连接channel建立成功后触发这个方法
                 */
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                    ch.pipeline().addLast(new HttpServerCodec());
                    // SimpleChannelInboundHandler会只关注泛型所指定的消息
                    ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpRequest>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
                            // 获取请求信息
                            log.info("uri: {}", msg.uri());

                            // 返回响应
                            // 构造参数: 参数1-指定请求版本, 请求时什么版本的http请求, 响应就是什么版本; 参数2-指定返回值状态码
                            DefaultFullHttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK);
                            // 构造消息内容
                            byte[] bytes = "<h1>hello world!</h1>".getBytes();
                            // 设置消息长度, 否则浏览器会一直转圈等待消息(因为不写入这个将会使浏览器不知道消息有多长)
                            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, bytes.length);
                            // 向响应体中写入内容
                            response.content().writeBytes(bytes);
                            // 向channel中写入数据, 这里返回response后, netty的HttpServerCodec会对其进行组装协议
                            ctx.writeAndFlush(response);
                        }
                    });
                    /*ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            log.info("类型: {}", msg.getClass());
                            if (msg instanceof HttpRequest) { // 处理请求行、请求头

                            } else if (msg instanceof HttpContent) { // 处理请求体

                            }
                        }
                    });*/
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("server error: ", e);
        } finally {
            bossEventLoopGroup.shutdownGracefully();
            workerEventLoopGroup.shutdownGracefully();
        }
    }
}
